package com.demo.base.web.webmvc;

import com.demo.base.bean.BaseOutput;
import com.demo.base.bean.CommonStatus;
import com.demo.base.exception.FrameworkException;
import com.demo.base.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.ClassUtils;
import org.springframework.web.bind.ServletRequestBindingException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletRequest;
import java.util.HashSet;
import java.util.Set;

/**
 * 全局异常处理器
 */
@ControllerAdvice
public class ExceptionAdvice {

    private static final Set<Class<? extends Exception>> UNCONCERNED_EXCEPTIONS =
            new HashSet<Class<? extends Exception>>() {{
                //参数异常
                add(IllegalStateException.class);
                add(IllegalArgumentException.class);

                //通常发生在开发阶段
                add(ServletRequestBindingException.class);
            }};

    private Logger logger = LoggerFactory.getLogger(getClass());

    private static boolean canShowMessage(Exception e) {
        Class<?> theClass = e.getClass();
        for (Class<? extends Exception> klass : UNCONCERNED_EXCEPTIONS) {
            if (theClass.equals(klass) || ClassUtils.isAssignable(klass, theClass)) {
                return true;
            }
        }
        return false;
    }

    @ResponseBody
    @ExceptionHandler(Exception.class)
    public BaseOutput errorHandler(Exception e, HttpServletRequest request) throws Exception {
        //日志处理
        JSONObject context = new JSONObject();
        context.put("url", request.getRequestURI());
        context.put("method", request.getMethod());
        context.put("message", e.getMessage());

        //返回结果
        if (e instanceof FrameworkException) {
            FrameworkException ex = (FrameworkException) e;
            logger.warn("处理失败：" + context.toJSONString(), e);
            return new BaseOutput(ex.getCode(), ex.getMessage());
        } else if (canShowMessage(e)) {
            logger.debug("验证失败：" + context.toJSONString(), e);
            return new BaseOutput(CommonStatus.BAD_REQUEST, e.getMessage());
        } else {
            logger.error("意外异常：" + context.toJSONString(), e);
            return new BaseOutput(CommonStatus.SERVER_ERROR);
        }
    }
}
